use actix_web::{App, HttpServer, middleware::Logger, web};
use r_oss::{AppState, Configuration, routers};
use tracing::{Subscriber, subscriber::set_global_default};
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
use tracing_log::LogTracer;
use tracing_subscriber::{EnvFilter, Registry, layer::SubscriberExt};

#[actix_web::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let configuration = Configuration::from_consul().await;
    let application_name = configuration.application_name();
    let address = configuration.server_address();
    let port = configuration.server_port();
    let logging_level = configuration.logging_level();
    let database_connection = configuration.database_connection().await?;

    let file_appender =
        tracing_appender::rolling::daily("logs", format!("{}.log", application_name));
    let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
    let file_layer = BunyanFormattingLayer::new(application_name.clone(), non_blocking);

    let env_filter =
        EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(logging_level));

    let subscriber = Registry::default()
        .with(env_filter)
        .with(JsonStorageLayer)
        .with(file_layer);

    init_subscriber(subscriber);

    let app_state = AppState {
        configuration,
        database_connection,
    };

    HttpServer::new(move || {
        App::new()
            .wrap(Logger::default())
            .app_data(web::Data::new(app_state.clone()))
            .configure(routers)
    })
    .bind((address, port))?
    .run()
    .await?;

    Ok(())
}

pub fn init_subscriber(subscriber: impl Subscriber + Send + Sync) {
    LogTracer::init().expect("Failed to set logger");
    set_global_default(subscriber).expect("Failed to set subscriber");
}
